﻿using System;
using System.Net;
using System.Net.Sockets;

namespace NeroConnect.Network
{
	/// <summary>Provides User Datagram Protocol (UDP) network services.</summary>
	public interface IUdpClient
	{
		/// <summary>Gets the amount of data received from the network that is available to read.</summary>
		/// <value>The number of bytes of data received from the network.</value>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred while attempting to access the socket. See the Remarks section for more information.</exception>
		/// <exception cref="System.ObjectDisposedException">The System.Net.Sockets.Socket has been closed.</exception>
		int Available { get; }

		/// <summary>Closes the UDP connection.</summary>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when accessing the socket. See the Remarks section for more information.</exception>
		void Close();

		/// <summary>Sends a UDP datagram to the host at the specified remote endpoint.</summary>
		/// <param name="data">An array of type System.Byte that specifies the UDP datagram that you intend to send, represented as an array of bytes.</param>
		/// <param name="bytes">The number of bytes in the datagram.</param>
		/// <param name="endPoint">An System.Net.IPEndPoint that represents the host and port to which to send the datagram.</param>
		/// <returns>The number of bytes sent.</returns>
		/// <exception cref="System.ArgumentNullException">data is null</exception>
		/// <exception cref="System.InvalidOperationException">IUdpClient has already established a default remote host.</exception>
		/// <exception cref="System.ObjectDisposedException">IUdpClient is closed.</exception>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when accessing the socket. See the Remarks section for more information.</exception>
		int Send(byte[] data, int bytes, IPEndPoint endPoint);

		/// <summary>Returns a UDP datagram that was sent by a remote host.</summary>
		/// <param name="remoteEndPoint">An System.Net.IPEndPoint that represents the remote host from which the data was sent.</param>
		/// <returns>An array of type System.Byte that contains datagram data.</returns>
		/// <exception cref="System.ObjectDisposedException">The underlying System.Net.Sockets.Socket has been closed.</exception>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when accessing the socket. See the Remarks section for more information.</exception>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
		byte[] Receive(ref IPEndPoint remoteEndPoint);

		/// <summary>Sends a datagram to a destination asynchronously. The destination is specified by a System.Net.EndPoint.</summary>
		/// <param name="data">A System.Byte array that contains the data to be sent.</param>
		/// <param name="bytes">The number of bytes to send.</param>
		/// <param name="endPoint">The System.Net.EndPoint that represents the destination for the data.</param>
		/// <param name="sendCallback">An System.AsyncCallback delegate that references the method to invoke when the operation is complete.</param>
		/// <param name="state">A user-defined object that contains information about the send operation. This object is passed to the requestCallback delegate when the operation is complete.</param>
		/// <returns>An System.IAsyncResult object that references the asynchronous send.</returns>
		IAsyncResult BeginSend(byte[] data, int bytes, IPEndPoint endPoint, AsyncCallback sendCallback, object state);

		/// <summary>Ends a pending asynchronous send.</summary>
		/// <param name="asyncResult">An System.IAsyncResult object returned by a call to Overload:System.Net.Sockets.UdpClient.BeginSend.</param>
		/// <returns>If successful, the number of bytes sent to the IUdpClient.</returns>
		/// <exception cref="System.ArgumentNullException">asyncResult is null.</exception>
		/// <exception cref="System.ArgumentException">asyncResult was not returned by a call to the BeginSend() method.</exception>
		/// <exception cref="System.InvalidOperationException">EndSend(System.IAsyncResult) was previously called for the asynchronous read.</exception>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when attempting to access the underlying socket. See the Remarks section for more information.</exception>
		/// <exception cref="System.ObjectDisposedException">The underlying System.Net.Sockets.Socket has been closed.</exception>
		int EndSend(IAsyncResult asyncResult);
		/// <summary>Receives a datagram from a remote host asynchronously.</summary>
		/// <param name="receiveCallback">An System.AsyncCallback delegate that references the method to invoke when the operation is complete.</param>
		/// <param name="state">A user-defined object that contains information about the receive operation. This object is passed to the requestCallback delegate when the operation is complete.</param>
		/// <returns>An System.IAsyncResult object that references the asynchronous receive.</returns>
		IAsyncResult BeginReceive(AsyncCallback receiveCallback, object state);
		/// <summary>Ends a pending asynchronous receive.</summary>
		/// <param name="asyncResult">An System.IAsyncResult object returned by a call to BeginReceive().</param>
		/// <param name="remoteEndPoint">The specified remote endpoint.</param>
		/// <returns>If successful, the number of bytes received. If unsuccessful, this method returns 0.</returns>
		/// <exception cref="System.ArgumentNullException">asyncResult is null.</exception>
		/// <exception cref="System.ArgumentException">asyncResult was not returned by a call to the BeginReceive() method.</exception>
		/// <exception cref="System.InvalidOperationException">EndReceive() was previously called for the asynchronous read.</exception>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when attempting to access the underlying System.Net.Sockets.Socket. See the Remarks section for more information.</exception>
		/// <exception cref="System.ObjectDisposedException">The underlying System.Net.Sockets.Socket has been closed.</exception>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
		byte[] EndReceive(IAsyncResult asyncResult, ref IPEndPoint remoteEndPoint);

		/// <summary>Adds a System.Net.Sockets.UdpClient to a multicast group.</summary>
		/// <param name="multicastAddress">The multicast System.Net.IPAddress of the group you want to join.</param>
		/// <exception cref="System.ObjectDisposedException">The underlying System.Net.Sockets.Socket has been closed.</exception>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when accessing the socket. See the Remarks section for more information.</exception>
		/// <exception cref="System.ArgumentException">The IP address is not compatible with the System.Net.Sockets.AddressFamily value that defines the addressing scheme of the socket.</exception>
		void JoinMulticastGroup(IPAddress multicastAddress);
		/// <summary>Leaves a multicast group.</summary>
		/// <param name="multicastAddress">The System.Net.IPAddress of the multicast group to leave.</param>
		/// <exception cref="System.ObjectDisposedException">The underlying System.Net.Sockets.Socket has been closed.</exception>
		/// <exception cref="System.Net.Sockets.SocketException">An error occurred when accessing the socket. See the Remarks section for more information.</exception>
		/// <exception cref="System.ArgumentException">The IP address is not compatible with the System.Net.Sockets.AddressFamily value that defines the addressing scheme of the socket.</exception>
		/// <exception cref="System.ArgumentNullException">multicastAddr is null.</exception>
		void DropMulticastGroup(IPAddress multicastAddress);
		/// <summary>Gets or sets a System.Boolean value that specifies whether outgoing multicast packets are delivered to the sending application.</summary>
		/// <value>true if the System.Net.Sockets.UdpClient receives outgoing multicast packets; otherwise, false.</value>
		bool MulticastLoopback { get; set; }

		/// <summary>Gets the underlying network System.Net.Sockets.Socket.</summary>
		/// <value>The underlying Network System.Net.Sockets.Socket.</value>
		Socket Client { get; }
	}
}
